#pragma once
#include <jsoncpp/json/json.h>
#include <signal.h>
#include <atomic>
#include "../common/common.hpp"
#include "compiler.hpp"
#include "run.hpp"

namespace wjh_compile_and_run
{
    using namespace wjh_util;

    class compile_and_run
    {
    public:
        compile_and_run(/* args */);
        ~compile_and_run();

        static void RemoveTempFile(std::string FileName)
        {
            std::string File_exe = Util::exe(FileName);
            if(Util::IsFileExits(File_exe)) unlink(File_exe.c_str());

            std::string File_compilerErr = Util::CompileErr(FileName);
            if(Util::IsFileExits(File_compilerErr)) unlink(File_compilerErr.c_str());

            std::string File_stdin = Util::stdIn(FileName);
            if(Util::IsFileExits(File_stdin)) unlink(File_stdin.c_str());

            std::string File_stdout = Util::stdOut(FileName);
            if(Util::IsFileExits(File_stdout)) unlink(File_stdout.c_str());

            std::string File_stderr = Util::stdErr(FileName);
            if(Util::IsFileExits(File_stderr)) unlink(File_stderr.c_str());
        }

        /**********************************************
        1.in_json是从oj_server通过网络传输过来，需要反序列化
            in_json格式{"code":"xxxx", "input":"xxxx", "cpuLimit":"xxx", "memLimit":"xxx"}
        2.生成具有唯一性的文件
        3.将code写入该文件
        4.编译并运行该文件, 并获取结果
        5.将结果序列化并返回
        序列化格式{(必填)"status":"xxx", "reason":"xxx", (选填)"stdin":"xxx", "stderr":"xxx"}
        ***********************************************/
        static void Start(std::string &in_json, std::string &out_json)
        {
            Json::Value in_value;
            Json::Reader jsonRead;
            jsonRead.parse(in_json, in_value);
            std::string code = in_value["code"].asString();
            std::string input = in_value["input"].asString();
            std::string FileName = UniqueFile();
            Json::Value out_value;
            Json::StyledWriter JsonWrite;

            int cpuLimit = in_value["cpuLimit"].asInt();
            int memLimit = in_value["memLimit"].asInt();
            int status;

            if (code.size() == 0)
            {
                // 提交空代码
                status = -2;
                goto END;
            }

            wjh_util::FileUtil::FileWrite(code, wjh_util::Util::src(FileName));
            if (!wjh_compiler::Compiler::Compile(FileName))
            {
                status = -3;
                goto END;
            }

            status = wjh_run::runner::Run(FileName, cpuLimit, memLimit);

        END:
            out_value["status"] = status;
            out_value["reason"] = StatusToDesc(status).c_str();
            if (status == 0)
            {
                std::string _stdout;
                FileUtil::FileRead(Util::stdOut(FileName), _stdout, true);
                out_value["stdout"] = _stdout.c_str();

                std::string _stderr;
                FileUtil::FileRead(Util::stdErr(FileName), _stderr, true);
                out_value["stderr"] = _stderr.c_str();
            }

            Json::StyledWriter Writer;
            out_json = Writer.write(out_value);

            RemoveTempFile(FileName);
        }

        static std::string UniqueFile()
        {
            //用毫秒级时间戳+原子性递增组成唯一文件
            std::atomic_uint au(0);
            au++;
            std::string ms = TimeUtil::getTimeMS();
            return ms + "_" + std::to_string(au);
        }

        static inline std::string StatusToDesc(int status)
        {
            switch (status)
            {
            case 0:
                // 编译运行成功
                return "运行成功";
                break;
            case -1:
                // 运行失败
                return "未知错误";
                break;
            case -2:
                // 提交空代码
                return "代码不能为空";
                break;
            case -3:
                // 编译失败
                return "编译时出现错误";
                break;
            case SIGABRT: //6
                return "超出内存限制";
                break;
            case SIGFPE: //8
                return "浮点数溢出";
                break;
            case SIGXCPU: //24
                return "超出时间限制";
                break;
            default:
                return std::to_string(status) + "未知错误";
                break;
            }
        }
    };

    compile_and_run::compile_and_run(/* args */)
    {
    }

    compile_and_run::~compile_and_run()
    {
    }

}